﻿using SqlSugar;
using SupplyChain.Infrastructure.Interface;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;

namespace SupplyChain.Infrastructure.Implement
{
    public class BaseRepository<T> : IBaseRepository<T> where T : class, new()
    {
        private readonly ISqlSugarClient client;

        public BaseRepository(ISqlSugarClient client)
        {
            this.client = client;
        }

        #region Add
        /// <summary>
        /// 增加单条数据
        /// </summary>
        /// <param name="model">实体对象</param>
        /// <returns>操作是否成功</returns>
        public async Task<bool> AddAsync(T model)
        {
            return await client.Insertable(model).ExecuteCommandAsync() > 0;
        }

        /// <summary>
        /// 增加多条数据
        /// </summary>
        /// <param name="list">实体集合</param>
        /// <returns>操作是否成功</returns>
        public async Task<bool> AddRangeAsync(List<T> list)
        {
            return await client.Insertable(list).ExecuteCommandAsync() > 0;
        }

        /// <summary>
        /// 添加单条数据，并返回 自增列
        /// </summary>
        /// <param name="model">实体对象</param>
        /// <returns></returns>
        public async Task<bool> AddReturnIdentityAsync(T model)
        {
            return await client.Insertable<T>(model).ExecuteReturnIdentityAsync() > 0;//ExecuteReturnBigIdentity();//4.5.0.2 +  long
        }

        /// <summary>
        /// 增加单条数据 ，并返回 实体
        /// </summary>
        /// <param name="model">实体对象</param>
        /// <returns></returns>
        public async Task<T> AddReturnEntityAsync(T model)
        {
            return await client.Insertable(model).ExecuteReturnEntityAsync();
        }

        /// <summary>
        /// 只添加指定列
        /// </summary>
        /// <param name="model">实体对象</param>
        /// <param name="columns">指定要添加的列</param>
        /// <returns></returns>
        public async Task<bool> AddColumnsAsync(T model, params string[] columns)
        {
            return await client.Insertable(model).InsertColumns(columns).ExecuteCommandAsync() > 0;
        }

        /// <summary>
        /// 不插入指定列
        /// </summary>
        /// <param name="model">实体对象</param>
        /// <param name="IgnoreColumns">要忽略的列</param>
        /// <returns></returns>
        public async Task<bool> AddColumnsByIgnoreColumnsAsync(T model, params string[] IgnoreColumns)
        {
            return await client.Insertable<T>(model)
                .IgnoreColumns(IgnoreColumns).ExecuteCommandAsync() > 0;
        }

        #endregion

        #region Delete

        /// <summary>
        /// 根据主键删除，并返回操作是否成功
        /// </summary>
        /// <typeparam name="S">主键的类型</typeparam>
        /// <param name="key">主键</param>
        /// <returns></returns>
        public async Task<bool> DeleteAsync<S>(S key)
        {
            return await client.Deleteable<T>().In(key).ExecuteCommandAsync() > 0;
        }

        /// <summary>
        /// 根据主键删除，并返回操作是否成功
        /// </summary>
        /// <typeparam name="S">主键类型</typeparam>
        /// <param name="keys">主键</param>
        /// <returns></returns>
        public async Task<bool> DeleteRangeAsync<S>(params S[] keys)
        {
            return await client.Deleteable<T>().In(keys).ExecuteCommandAsync() > 0;
        }

        /// <summary>
        /// 根据条件删除，并返回操作是否成功
        /// </summary>
        /// <param name="where">条件</param>
        /// <returns></returns>
        public async Task<bool> DeleteWhereAsync(Expression<Func<T, bool>> where)
        {
            return await client.Deleteable<T>().Where(where).ExecuteCommandAsync() > 0;
        }

        #endregion

        #region Update

        /// <summary>
        /// 根据主键更新 ，返回操作是否成功
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        public async Task<bool> UpdateAsync(T model)
        {
            return await client.Updateable<T>(model).ExecuteCommandAsync() > 0;
        }

        /// <summary>
        /// 根据主键更新，返回操作是否成功
        /// </summary>
        /// <param name="list">实体集合</param>
        /// <returns></returns>
        public async Task<bool> UpdateRangeAsync(List<T> list)
        {
            return await client.Updateable<T>(list).ExecuteCommandAsync() > 0;
        }

        /// <summary>
        /// 根据指定 列条件 更新 ，并返回操作是否成功
        /// </summary>
        /// <param name="model">实体对象</param>
        /// <param name="expression">列条件 例如： t=>t.id>5 </param>
        public async Task<bool> UpdateAsync(T model, Expression<Func<T, object>> expression)
        {
            return await client.Updateable<T>(model).WhereColumns(expression).ExecuteCommandAsync() > 0;
        }

        /// <summary>
        /// 根据主键，更新指定列,返回操作是否成功
        /// </summary>
        /// <param name="model">实体对象</param>
        /// <param name="columns">要更新的列</param>
        /// <returns></returns>
        public async Task<bool> UpdateColumnsAsync(T model, params string[] columns)
        {
            return await client.Updateable<T>(model).UpdateColumns(columns).ExecuteCommandAsync() > 0;
        }

        /// <summary>
        /// 根据主键，更新指定列,返回操作是否成功
        /// </summary>
        /// <param name="model">实体对象</param>
        /// <param name="columns">要更新的列</param>
        /// <returns></returns>
        public async Task<bool> UpdateColumnsAsync(T model, Expression<Func<T, object>> columns)
        {
            return await client.Updateable<T>(model).UpdateColumns(columns).ExecuteCommandAsync() > 0;
        }

        /// <summary>
        /// 根据主键 ， 忽略更新指定列，返回操作是否成功
        /// </summary>
        /// <param name="model">实体对象</param>
        /// <param name="columns">不更新的 忽略列</param>
        /// <returns></returns>
        public async Task<bool> UpdateColumnsByIgnoreColumnsAsync(T model, params string[] columns)
        {
            return await client.Updateable<T>(model).IgnoreColumns(columns).ExecuteCommandAsync() > 0;
        }

        /// <summary>
        /// 根据主键 ， 忽略更新指定列，返回操作是否成功
        /// </summary>
        /// <param name="model">实体对象</param>
        /// <param name="columns">不更新的 忽略列</param>
        /// <returns></returns>
        public async Task<bool> UpdateColumnsByIgnoreColumnsAsync(T model, Expression<Func<T, object>> columns)
        {
            return await client.Updateable<T>(model).IgnoreColumns(columns).ExecuteCommandAsync() > 0;
        }

        /// <summary>
        /// 根据主键更新 列
        /// </summary>
        /// <param name="model">实体对象</param>
        /// <param name="ignoreAllNullColumns">是否 NULL的列不更新</param>
        /// <param name="isOffIdentity">是否忽略 自增列</param>
        /// <param name="ignoreAllDefaultValue">是否 忽略默认值列</param>
        /// <returns></returns>
        public async Task<bool> UpdateNotNullColumnsAsync(T model, bool ignoreAllNullColumns, bool isOffIdentity = false, bool ignoreAllDefaultValue = false)
        {
            return await client.Updateable<T>()
                .IgnoreColumns(ignoreAllNullColumns: true, isOffIdentity: false, ignoreAllDefaultValue: false)
                .ExecuteCommandAsync() > 0;
        }

        //4.6.0.7 联表更新

        /// <summary>
        /// //根据不同条件执行更新不同的列 
        /// </summary>
        /// <param name="model">实体对象</param>
        /// <param name="dic">条件（key：要更新的列，value：条件是否更新此列）</param>
        /// <returns></returns>
        public async Task<bool> UpdateIFAsync(T model, Dictionary<Expression<Func<T, object>>, bool> dic)
        {
            var able = client.Updateable<T>(model);
            foreach (var item in dic)
            {
                able.UpdateColumnsIF(item.Value, item.Key);// s=>s.name  ture
            }

            return await able.ExecuteCommandAsync() > 0;
        }

        #endregion

        #region Query

        /// <summary>
        /// 查询所有数据
        /// </summary>
        /// <returns></returns>
        public async Task<List<T>> GetAllAsync(bool isOrderBy = false, Expression<Func<T, object>> orderBy = null, OrderByType orderByType = OrderByType.Asc)
        {
            return await client.Queryable<T>().OrderByIF(isOrderBy, orderBy, orderByType).ToListAsync();
        }

        /// <summary>
        /// 取前 num 条数据
        /// </summary>
        /// <param name="num">取前几条</param>
        /// <returns></returns>
        public async Task<List<T>> GetTakeListAsync(int num, bool isOrderBy = false, Expression<Func<T, object>> orderBy = null, OrderByType orderByType = OrderByType.Asc)
        {
            return await client.Queryable<T>().OrderByIF(isOrderBy, orderBy, orderByType).Take(num).ToListAsync();
        }

        /// <summary>
        /// 获取单表 分页数据
        /// </summary>
        /// <param name="skip">跳过几条</param>
        /// <param name="take">取几条</param>
        /// <param name="whereExp">跳过几条</param>
        /// <param name="orderBy">排序条件</param>
        /// <param name="orderByType">排序类型（Asc、Desc）</param>
        /// <returns></returns>
        public async Task<List<T>> GetPageListAsync(int skip, int take, Expression<Func<T, bool>> whereExp, Expression<Func<T, object>> orderBy, OrderByType orderByType = OrderByType.Asc)
        {
            return await client.Queryable<T>().Skip(skip).Take(take).OrderBy(orderBy, orderByType).ToListAsync();
        }

        /// <summary>
        /// 获取符合条件的前 num 条数据
        /// </summary>
        /// <param name="where">条件</param>
        /// <param name="num">取前几条</param>
        /// <returns></returns> 
        public async Task<List<T>> GetTakeListAsync(Expression<Func<T, bool>> where, int num, bool isOrderBy = false, Expression<Func<T, object>> orderBy = null, OrderByType orderByType = OrderByType.Asc)
        {
            return await client.Queryable<T>().Where(where).OrderByIF(isOrderBy, orderBy, orderByType).Take(num).ToListAsync();
        }

        /// <summary>
        /// 根据主键查询
        /// </summary>
        /// <param name="pkValue">主键</param>
        /// <returns></returns>
        public async Task<T> GetByPrimaryKeyAsync(object pkValue)
        {
            return await client.Queryable<T>().InSingleAsync(pkValue);
        }

        /// <summary>
        /// 根据条件获取 单条数据 
        /// </summary>
        /// <param name="where">条件</param>
        /// <returns></returns>
        public async Task<T> GetFirstOrDefaultAsync(Expression<Func<T, bool>> where)
        {
            return await client.Queryable<T>().FirstAsync(where);//查询单条没有数据返回NULL, Single超过1条会报错，First不会
        }

        /// <summary>
        /// 根据条件 查询
        /// </summary>
        /// <param name="where">条件</param>
        /// <returns></returns>
        public async Task<List<T>> GetByWhereAsync(Expression<Func<T, bool>> where, bool isOrderBy = false, Expression<Func<T, object>> orderBy = null, OrderByType orderByType = OrderByType.Asc)
        {
            return await client.Queryable<T>().Where(where).OrderByIF(isOrderBy, orderBy, orderByType).ToListAsync();
        }

        /// <summary>
        /// 查询 指定列的值 在 start至end 之间的数据
        /// </summary>
        /// <param name="value">指定类</param>
        /// <param name="start">开始</param>
        /// <param name="end">结束</param>
        /// <returns></returns>
        public async Task<List<T>> GetByBetweenAsync(object value, object start, object end, bool isOrderBy = false, Expression<Func<T, object>> orderBy = null, OrderByType orderByType = OrderByType.Asc)
        {
            return await client.Queryable<T>().Where(it => SqlFunc.Between(value, start, end)).OrderByIF(isOrderBy, orderBy, orderByType).ToListAsync();
        }

        /// <summary>
        /// 判断是否存在这条记录
        /// </summary>
        /// <param name="where">条件</param>
        /// <returns></returns>
        public async Task<bool> GetIsAnyAsync(Expression<Func<T, bool>> where)
        {
            return await client.Queryable<T>().AnyAsync(where);
        }

        /// <summary>
        /// 单表分页查询
        /// </summary>
        /// <typeparam name="T">要查询的表</typeparam>
        /// <param name="pageIndex">页码</param>
        /// <param name="pageSize">页面容量</param>
        /// <param name="isWhere">是否需要条件查询</param>
        /// <param name="whereExp">查询条件</param>
        /// <param name="isOrderBy">是否需要排序条件</param>
        /// <param name="orderBy">排序条件</param>
        /// <param name="orderByType">排序类型（Asc、Desc）</param>
        /// <returns></returns>
        public async Task<List<T>> GetPageListAsync<T>(int pageIndex, int pageSize, bool isWhere = false, Expression<Func<T, bool>> whereExp = null, bool isOrderBy = false, Expression<Func<T, object>> orderBy = null, OrderByType orderByType = OrderByType.Asc)
        {
            return await client.Queryable<T>().WhereIF(isWhere, whereExp).OrderByIF(isOrderBy, orderBy, orderByType).ToPageListAsync(pageIndex, pageSize);
        }

        /// <summary>
        /// 两表查询，
        /// </summary>
        /// <typeparam name="T1">左表</typeparam>
        /// <typeparam name="T2">右表</typeparam>
        /// <param name="joinExp">联表方式，联表字段（主外键关系）</param>
        /// <param name="selectExp">联表查询的结果</param>
        /// <param name="isWhere">是否需要查询条件</param>
        /// <param name="whereExp">条件查询</param>
        /// <param name="isOrderBy">是否需要排序</param>
        /// <param name="orderBy">排序条件</param>
        /// <param name="orderByType">排序类型（Asc、Desc）</param>
        /// <returns></returns>
        public async Task<dynamic> getJoinList<T1, T2>(Expression<Func<T1, T2, JoinQueryInfos>> joinExp, Expression<Func<T1, T2, dynamic>> selectExp, bool isWhere = false, Expression<Func<T1, T2, bool>> whereExp = null, bool isOrderBy = false, Expression<Func<T1, T2, object>> orderBy = null, OrderByType orderByType = OrderByType.Asc)
        {

            return await client.Queryable<T1, T2>(joinExp).WhereIF(isWhere, whereExp)
                .OrderByIF(isOrderBy, orderBy, orderByType).Select(selectExp).ToListAsync();
        }

        /// <summary>
        /// 两表 分页查询，
        /// </summary>
        /// <typeparam name="T1">左表</typeparam>
        /// <typeparam name="T2">右表</typeparam>
        /// <param name="joinExp">联表方式，联表字段（主外键关系）</param>
        /// <param name="selectExp">联表查询的结果</param>
        /// <param name="isWhere">是否需要查询条件</param>
        /// <param name="whereExp">条件查询</param>
        /// <param name="isOrderBy">是否需要排序</param>
        /// <param name="orderBy">排序条件</param>
        /// <param name="orderByType">排序类型（Asc、Desc）</param>
        /// <returns></returns>
        public async Task<dynamic> getJoinPageList<T1, T2>(int pageIndex, int pageSize, Expression<Func<T1, T2, JoinQueryInfos>> joinExp, Expression<Func<T1, T2, dynamic>> selectExp, bool isWhere = false, Expression<Func<T1, T2, bool>> whereExp = null, bool isOrderBy = false, Expression<Func<T1, T2, object>> orderBy = null, OrderByType orderByType = OrderByType.Asc)
        {
            return await client.Queryable(joinExp).WhereIF(isWhere, whereExp)
                .OrderByIF(isOrderBy, orderBy, orderByType).Select(selectExp).ToPageListAsync(pageIndex, pageSize);
        }


        /// <summary>
        /// 执行查询sql语句 ，返回数据集
        /// </summary>
        /// <param name="sql">sql语句</param>
        /// <returns></returns>
        public async Task<List<T>> GetListBySqlAsync(string sql)
        {
            return await client.SqlQueryable<T>(sql).ToListAsync();
        }

        /// <summary>
        /// 执行非查询sql语句，返回操作是否成功
        /// </summary>
        /// <param name="sql">sql语句</param>
        /// <param name="parameters">参数化</param>
        /// <returns></returns>
        public async Task<bool> ExecuteCommandSqlAsync(string sql, params SugarParameter[] parameters)
        {
            return await client.Ado.ExecuteCommandAsync(sql, parameters) > 0;
        }

        /// <summary>
        /// 执行查询sql语句，返回查询的结果集
        /// </summary>
        /// <param name="sql">sql语句</param>
        /// <param name="parameters">参数化</param>
        /// <returns></returns>
        public async Task<List<T>> GetListBySqlQueryAsync(string sql, params SugarParameter[] parameters)
        {
            return await client.Ado.SqlQueryAsync<T>(sql, parameters);
        }

        /// <summary>
        /// 执行查询sql语句，返回 第一行第一列
        /// </summary>
        /// <param name="sql">sql语句</param>
        /// <param name="parameters">参数化</param>
        /// <returns></returns>
        public async Task<object> GetScalarAsync(string sql, params SugarParameter[] parameters)
        {
            return await client.Ado.GetScalarAsync(sql, parameters);
        }

        #endregion
    }
}
